package com.boesch.electroOffice.presentation.appointment;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.event.ActionEvent;
import javax.faces.event.ComponentSystemEvent;
import javax.faces.model.SelectItem;

import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import com.boesch.electroOffice.business.businessObject.WorkingHoursBusinessObject;
import com.boesch.electroOffice.business.common.BusinessException;
import com.boesch.electroOffice.dataaccess.common.IllegalDataAccessException;
import com.boesch.electroOffice.model.enums.SessionParameter;
import com.boesch.electroOffice.model.wrapper.WorkingHoursEntry;
import com.boesch.electroOffice.utils.DateUtils;
import com.boesch.electroOffice.utils.MessageUtils;
import com.boesch.electroOffice.utils.PortletUtils;
import com.boesch.electroOffice.utils.UserUtils;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.model.User;

@Controller
@ManagedBean
@SessionScoped
public class WorkingHoursController implements Serializable {

	private static final long serialVersionUID = 8034571075108913453L;
	private static final Log log = LogFactoryUtil.getLog(WorkingHoursController.class);

	@Autowired
	private WorkingHoursBusinessObject workingHoursBusinessObject;

	private List<WorkingHoursEntry> workingHourEntries = new ArrayList<WorkingHoursEntry>();

	private List<SelectItem> selectItemUsers = new ArrayList<SelectItem>();

	private WorkingHoursEntry defaultWorkingHoursEntry;

	private LocalDate workingHoursDateMonday;
	private Date chosenDate;

	private Integer appointmentId;
	private Long selectedUserId = -1L;

	private double totalProdMonday;
	private double totalProdTuesday;
	private double totalProdWednesday;
	private double totalProdThursday;
	private double totalProdFriday;
	private double totalProdSaturday;
	private double totalProdSunday;
	private double totalProdTotal;

	public void loadData(ComponentSystemEvent event) {
		String appId = PortletUtils.getSessionAttribute(SessionParameter.APPOINTMENT_ID.getValue());
		appointmentId = StringUtils.isNumeric(appId) ? Integer.parseInt(appId) : -1;
		try {
			clearTotalProdHours();
			if (null == workingHoursDateMonday || "true".equals(PortletUtils.getSessionAttribute(SessionParameter.RESET.getValue()))) {
				this.workingHoursDateMonday = DateUtils.getDateOfMondayInCurrentWeek();
				PortletUtils.setSessionAttribute(SessionParameter.RESET.getValue(), "false");
			}
			int year = DateUtils.getYearByLocalDate(workingHoursDateMonday);
			int week = DateUtils.getWeekByLocalDate(workingHoursDateMonday);
			this.workingHourEntries = workingHoursBusinessObject.getWorkingHourEntriesByAppointmentIdAndCalendarWeek(appointmentId, year, week);
			for (WorkingHoursEntry entry : workingHourEntries) {
				if (entry.getIsDefault()) {
					this.defaultWorkingHoursEntry = entry;
					break;
				}
			}
			this.selectedUserId = null != defaultWorkingHoursEntry.getUser() ? defaultWorkingHoursEntry.getUser().getUserId() : 0L;
			calculateTotalProdHours();
			initializeSelectItemUsers();
		} catch (IllegalDataAccessException e) {
			log.error("Failed to load workingHours for appointment: " + appointmentId, e);
		} catch (BusinessException e) {
			log.error("Failed to load workingHours for appointment: " + appointmentId, e);
		}
	}

	public void saveWorkingHoursEntry() {
		if (validateDefaultWorkingHour()) {
			this.defaultWorkingHoursEntry.setUser(getUserBySelectedUserId());
			// Set appointmentId to each workingHours object
			this.defaultWorkingHoursEntry.getMonday().setAppointmentId(appointmentId);
			this.defaultWorkingHoursEntry.getTuesday().setAppointmentId(appointmentId);
			this.defaultWorkingHoursEntry.getWednesday().setAppointmentId(appointmentId);
			this.defaultWorkingHoursEntry.getThursday().setAppointmentId(appointmentId);
			this.defaultWorkingHoursEntry.getFriday().setAppointmentId(appointmentId);
			this.defaultWorkingHoursEntry.getSaturday().setAppointmentId(appointmentId);
			this.defaultWorkingHoursEntry.getSunday().setAppointmentId(appointmentId);
			// Set userId to each workingHours object
			this.defaultWorkingHoursEntry.getMonday().setLrUserId(selectedUserId);
			this.defaultWorkingHoursEntry.getTuesday().setLrUserId(selectedUserId);
			this.defaultWorkingHoursEntry.getWednesday().setLrUserId(selectedUserId);
			this.defaultWorkingHoursEntry.getThursday().setLrUserId(selectedUserId);
			this.defaultWorkingHoursEntry.getFriday().setLrUserId(selectedUserId);
			this.defaultWorkingHoursEntry.getSaturday().setLrUserId(selectedUserId);
			this.defaultWorkingHoursEntry.getSunday().setLrUserId(selectedUserId);
			try {
				workingHoursBusinessObject.saveWorkingHoursEntry(defaultWorkingHoursEntry, UserUtils.getCurrentUser());
			} catch (IllegalDataAccessException e) {
				log.error("Failed to save workingHoursEntry!", e);
				MessageUtils.addErrorMessage("Speichern der Arbeitsstunden fehlgeschlagen.");
			} catch (BusinessException e) {
				log.error("Failed to save workingHoursEntry!", e);
				MessageUtils.addErrorMessage("Speichern der Arbeitsstunden fehlgeschlagen.");
			}
		} else {
			MessageUtils.addErrorMessage("Bitte füllen Sie mindestens ein Feld mit Arbeitsstunden");
		}
	}

	public void cancel() {
		this.defaultWorkingHoursEntry.getMonday().setHours(0.0);
		this.defaultWorkingHoursEntry.getTuesday().setHours(0.0);
		this.defaultWorkingHoursEntry.getWednesday().setHours(0.0);
		this.defaultWorkingHoursEntry.getThursday().setHours(0.0);
		this.defaultWorkingHoursEntry.getFriday().setHours(0.0);
		this.defaultWorkingHoursEntry.getSaturday().setHours(0.0);
		this.defaultWorkingHoursEntry.getSunday().setHours(0.0);
	}

	public void deleteWorkingHoursEntry() {
		System.out.println("Eintrag löschen");
	}

	public List<WorkingHoursEntry> getWorkingHourEntries() {
		return workingHourEntries;
	}

	public WorkingHoursEntry getDefaultWorkingHoursEntry() {
		return defaultWorkingHoursEntry;
	}

	public int getCalendarWeek() {
		return DateUtils.getWeekByLocalDate(workingHoursDateMonday);
	}

	public String getWorkingHoursDateMondayString() {
		return DateUtils.convertLocalDateToString(workingHoursDateMonday);
	}

	public String getWorkingHoursDateSundayString() {
		LocalDate sunday = DateUtils.getDatePlusDays(workingHoursDateMonday, 6);
		return DateUtils.convertLocalDateToString(sunday);
	}

	public void navigateWeekForward(ActionEvent event) {
		this.workingHoursDateMonday = DateUtils.getDatePlusDays(workingHoursDateMonday, 7);
	}

	public void navigateWeekBackward(ActionEvent event) {
		this.workingHoursDateMonday = DateUtils.getDateMinusDays(workingHoursDateMonday, 7);
	}

	public void navigateToCurrentWeek() {
		this.workingHoursDateMonday = DateUtils.getDateOfMondayInCurrentWeek();
	}

	public void showWeekByDate() {
		if (null != chosenDate) {
			LocalDate date = DateUtils.convertDateToLocalDate(chosenDate);
			this.workingHoursDateMonday = DateUtils.getDateOfMondayByLocalDate(date);
		}
	}

	public List<SelectItem> getUserList() {
		return selectItemUsers;
	}

	public long getSelectedUserId() {
		return selectedUserId;
	}

	public void setSelectedUserId(long selectedUserId) {
		this.selectedUserId = selectedUserId;
	}

	public Date getChosenDate() {
		return chosenDate;
	}

	public void setChosenDate(Date chosenDate) {
		this.chosenDate = chosenDate;
	}

	public double getTotalProdMonday() {
		return totalProdMonday;
	}

	public double getTotalProdTuesday() {
		return totalProdTuesday;
	}

	public double getTotalProdWednesday() {
		return totalProdWednesday;
	}

	public double getTotalProdThursday() {
		return totalProdThursday;
	}

	public double getTotalProdFriday() {
		return totalProdFriday;
	}

	public double getTotalProdSaturday() {
		return totalProdSaturday;
	}

	public double getTotalProdSunday() {
		return totalProdSunday;
	}

	public double getTotalProdTotal() {
		return totalProdTotal;
	}

	private void calculateTotalProdHours() {
		for (WorkingHoursEntry entry : workingHourEntries) {
			this.totalProdMonday = totalProdMonday + (null != entry.getMonday() ? entry.getMonday().getHours() : 0.0);
			this.totalProdTuesday = totalProdTuesday + (null != entry.getTuesday() ? entry.getTuesday().getHours() : 0.0);
			this.totalProdWednesday = totalProdWednesday + (null != entry.getWednesday() ? entry.getWednesday().getHours() : 0.0);
			this.totalProdThursday = totalProdThursday + (null != entry.getThursday() ? entry.getThursday().getHours() : 0.0);
			this.totalProdFriday = totalProdFriday + (null != entry.getFriday() ? entry.getFriday().getHours() : 0.0);
			this.totalProdSaturday = totalProdSaturday + (null != entry.getSaturday() ? entry.getSaturday().getHours() : 0.0);
			this.totalProdSunday = totalProdSunday + (null != entry.getSunday() ? entry.getSunday().getHours() : 0.0);
		}
		this.totalProdTotal = totalProdMonday + totalProdTuesday + totalProdWednesday + totalProdThursday + totalProdFriday + totalProdSaturday + totalProdSunday;
	}

	private void clearTotalProdHours() {
		this.totalProdMonday = 0;
		this.totalProdTuesday = 0;
		this.totalProdWednesday = 0;
		this.totalProdThursday = 0;
		this.totalProdFriday = 0;
		this.totalProdSaturday = 0;
		this.totalProdSunday = 0;
		this.totalProdTotal = 0;
	}

	private void initializeSelectItemUsers() {
		try {
			selectItemUsers = new ArrayList<SelectItem>();
			List<User> users = UserUtils.getAllBoeschUsers();
			for (User user : users) {
				String userId = String.valueOf(user.getUserId());
				String fullName = user.getFullName();
				String comment = user.getComments();
				SelectItem item = new SelectItem(userId, fullName, comment);
				selectItemUsers.add(item);
			}
		} catch (SystemException e) {
			log.error("Failed to load users from liferay database.", e);
		}
	}

	private User getUserBySelectedUserId() {
		List<User> users = new ArrayList<User>();
		try {
			users = UserUtils.getAllBoeschUsers();
			for (User user : users) {
				if (selectedUserId == user.getUserId()) {
					return user;
				}
			}
		} catch (SystemException e) {
			log.error("Failed to load Users from Liferay database.", e);
		}
		return null;
	}

	private boolean validateDefaultWorkingHour() {
		double monday = null != defaultWorkingHoursEntry.getMonday() ? defaultWorkingHoursEntry.getMonday().getHours() : 0.0;
		double tuesday = null != defaultWorkingHoursEntry.getTuesday() ? defaultWorkingHoursEntry.getTuesday().getHours() : 0.0;
		double wednesday = null != defaultWorkingHoursEntry.getWednesday() ? defaultWorkingHoursEntry.getWednesday().getHours() : 0.0;
		double thursday = null != defaultWorkingHoursEntry.getThursday() ? defaultWorkingHoursEntry.getThursday().getHours() : 0.0;
		double friday = null != defaultWorkingHoursEntry.getFriday() ? defaultWorkingHoursEntry.getFriday().getHours() : 0.0;
		double saturday = null != defaultWorkingHoursEntry.getSaturday() ? defaultWorkingHoursEntry.getSaturday().getHours() : 0.0;
		double sunday = null != defaultWorkingHoursEntry.getSunday() ? defaultWorkingHoursEntry.getSunday().getHours() : 0.0;
		return (monday + tuesday + wednesday + thursday + friday + saturday + sunday) > 0.0;
	}
}
